/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package parser;

import java.util.List;

import common.Constants;

import structures.grammar.Rule;
import structures.parserStructures.ParseError;
import structures.parserStructures.ParserOutput;
import structures.parserStructures.Stack;
import structures.parserStructures.StackElem;
import structures.table.LRTable;
import structures.table.action.Accept;
import structures.table.action.Action;
import structures.table.action.Reduce;
import structures.table.action.Shift;
import structures.table.symboltable.ItemInfo;
import structures.tree.ParseTreeNode;

/**
 *
 * @author Slayer
 */
public class Parser implements ParserInterface {

    private LRTable actionTable;
    private LRTable gotoTable;

    public Parser(LRTable actionTable, LRTable gotoTable) {
        this.actionTable = actionTable;
        this.gotoTable = gotoTable;
    }

    @Override
    public ParserOutput parse(List<ItemInfo> input) {
        Stack stack = new Stack();
        int curState;
        stack.push(new StackElem(null, 0)); // INITIALISATION
        
        input.add(Constants.MARKER);

        for (ItemInfo item : input) {
            do {
                curState = stack.getHead().getState();
                Action<?> action = actionTable.get(curState, item);
                
                if (action == null) {
                    return new ParserOutput(ParseError.ERROR);
                }
                
                if (action instanceof Shift) {
                    stack.push(new StackElem(new ParseTreeNode(item), (Integer) action.getValue()));
                    break;
                }
                
                if (action instanceof Reduce) {
                    Rule rule = (Rule) action.getValue();
                    List<ParseTreeNode> leaves = stack.popM(rule.length());
                    curState = stack.getHead().getState();
                    Action<?> goTo = gotoTable.get(curState, rule.getFrom());
                    
                    if (goTo == null) {
                        return new ParserOutput(ParseError.ERROR);
                    }
                    
                    int nextState = (Integer) goTo.getValue();
                    stack.push(new StackElem(new ParseTreeNode(rule.getFrom(), leaves), nextState));
                }
                
                if (action instanceof Accept) {
                    return new ParserOutput(stack.getHead().getNode());
                }
            } while (true);
        }
        return new ParserOutput(ParseError.ERROR);
    }
}
